package main

import (
	"fmt"
	"time"
	"Go-Exercise/immoc/retriever/real"
	"Go-Exercise/immoc/retriever/mock"
)

/**
	1.接口，它里面有两个东西，一个是实现者的类型，一个是实现者的值，可以是一个真实的值，
	也可以是一个指针，如果是一个真实的值，很显然是拷贝的数据。

	2.接口变量自带指针

	3.接口变量同样采用值传递,几乎不需要使用接口的指针

	4.指针接受者的实现只能以指针方式使用;值接受者都可以
 */
type Retriever interface {
	Get(url string) string
}

type Poster interface {
	Post(url string, form map[string]string) string
}

const url = "http://www.imooc.com"

func download(r Retriever) string {
	return r.Get(url)
}

func post(poster Poster) {
	poster.Post(url, map[string]string{
		"name":   "ccmouse",
		"course": "golang",
	})
}

/**
	接口的组合的作用:
	1.接口的组合是由使用者来说的
	2.使用者可以自定义里面有什么方法，也可以把现有的一些接口组合起来
	3.而实现者只管实现所要的一个方法

 */
type RetrieverPoster interface {
	Retriever
	Poster
}

func session(s RetrieverPoster) string {
	s.Post(url, map[string]string{
		"contents": "another faked imooc.com",
	})

	return s.Get(url)
}

func main() {
	var r Retriever
	retriever :=
		mock.Retriever{"this is a fake imooc.com"}
	r = &retriever
	inspect(r)

	r = &real.Retriever{
		UserAgent: "Mozilla/5.0",
		TimeOut:   time.Minute,
	}

	inspect(r)

	// Type assertion ,查看接口变量
	if mockRetriever, ok := r.(*mock.Retriever); ok {
		fmt.Println(mockRetriever.Contents)

	} else {
		fmt.Println("not a mock retriever")
	}

	fmt.Println("Try a session")
	fmt.Println(session(&retriever))
	//fmt.Println(download(r))
}

/**
	类型
 */
func inspect(r Retriever) {
	fmt.Println("Inspecting",r)
	switch v := r.(type) {



	case *mock.Retriever:
		fmt.Println(" > Contents:", v.Contents)
	case *real.Retriever:
		fmt.Println(" > UserAgent:", v.UserAgent)
		fmt.Println(" > UserAgent:", v.UserAgent)

	}
	fmt.Println()
}
